package jmine.tec.security.josso.gateway.servlet;

import static jmine.tec.security.josso.JOSSOSecurityException.BUNDLE;
import static jmine.tec.security.josso.gateway.auth.SecurityManagerAuthScheme.SCHEME_NAME;
import static org.josso.gateway.signon.Constants.KEY_JOSSO_SECURITY_DOMAIN_NAME;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import jmine.tec.security.josso.JOSSOHelper;
import jmine.tec.security.josso.JOSSOSecurityException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.josso.gateway.MutableSSOContext;
import org.josso.gateway.SSOException;
import org.josso.gateway.SSOGateway;
import org.josso.gateway.SSORequestImpl;
import org.josso.gateway.assertion.AuthenticationAssertion;
import org.josso.gateway.identity.exceptions.NoSuchDomainException;
import org.josso.gateway.session.SSOSession;
import org.josso.gateway.session.exceptions.NoSuchSessionException;
import org.josso.gateway.signon.Constants;

import bancosys.tec.exception.MessageHolder;
import bancosys.tec.security.SecurityException;
import bancosys.tec.security.impl.web.servlet.SecurityServlet;

/**
 * Servlet que lida com login utilizando JOSSO
 * 
 * @author lundberg
 */
public class JOSSOGatewayServlet extends SecurityServlet {

    private static final Log LOG = LogFactory.getLog(JOSSOGatewayServlet.class);

    /**
     * {@inheritDoc}
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        SSOGateway gateway = JOSSOHelper.getSSOGateway(request.getSession().getServletContext());
        MutableSSOContext ssoContext;
        try {
            ssoContext = this.createSSOContext(request, gateway);
        } catch (SecurityException e) {
            LOG.error(e.getMessage(), e);
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            return;
        }
        String jossoSessionId = JOSSOHelper.getJossoSessionId(request);
        String backTo = request.getParameter(Constants.PARAM_JOSSO_BACK_TO);
        if (jossoSessionId == null) {
            LOG.warn("Requisição de autenticação via Gateway feita sem JOSSO Session ID associado.");
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
            return;
        }
        if (backTo == null) {
            LOG.warn("Requisição de autenticação via Gateway feita URL de volta.");
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
            return;
        }

        try {
            SSOSession session = gateway.findSession(jossoSessionId);
            ssoContext.setCurrentSession(session);
            AuthenticationAssertion authAssertion = gateway.assertIdentity(session.getId());

            backTo += (backTo.indexOf("?") >= 0 ? "&" : "?") + "josso_assertion_id=" + authAssertion.getId();
            response.sendRedirect(backTo);
        } catch (NoSuchSessionException e) {
            LOG.warn("Sessão não encontrada com JOSSO Session ID " + jossoSessionId);
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
        } catch (SSOException e) {
            LOG.error(e.getMessage(), e);
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * Prepara o contexto para login
     * 
     * @param request request
     * @param gateway gateway
     * @return SSO Context
     * @throws SecurityException SecurityException
     */
    private MutableSSOContext createSSOContext(HttpServletRequest request, SSOGateway gateway) throws SecurityException {
        try {
            MutableSSOContext ssoContext = (MutableSSOContext) gateway.prepareSSOContext(new SSORequestImpl(request));
            ssoContext.setUserLocation(request.getRemoteHost());
            request.getSession().setAttribute(KEY_JOSSO_SECURITY_DOMAIN_NAME, ssoContext.getSecurityDomain().getName());
            ssoContext.setScheme(SCHEME_NAME);
            return ssoContext;
        } catch (NoSuchDomainException e) {
            LOG.error(e.getMessage(), e);
            throw new JOSSOSecurityException(new MessageHolder(BUNDLE, "jmine.tec.security.josso.no.such.domain"), e);
        }
    }

}
